/*************************************************************
 * File: Role.java
 * Copyright (c) 2012
 * Author: Huang Shaobin
 * Email: Shaobin.Software@gmail.com Shaobin_Software@163.com 
 * Date: Feb 3, 2013
 * Description: 
 ************************************************************/

package snow.biz.security.model;

import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;

import snow.biz.base.model.BaseEntity;
import snow.biz.system.model.Group;
import snow.biz.system.model.User;
import snow.core.enums.Status;
import snow.core.security.OperationType;
import snow.core.security.SecurityHelper;

/**
 * 系统角色实体
 * 
 * @author Shaobin.Software@gmail.com Shaobin_Software@163.com
 * @version 1.0
 */
public class Role extends BaseEntity<Integer> {

	/**
	 * 
	 */
	private static final long serialVersionUID = -39410512836031628L;

	private Group group; // 所属集团
	private String name; // 角色名称
	private String desc; // 角色描述
	private Map<Resource, Operation> operations; // 拥有的权限

	protected Role() {
		super();
	}

	public Role(User createUser, Group group, String name, String desc, Map<Resource, Set<OperationType>> operations) {
		super(createUser);
		this.group = group;
		setName(name);
		setDesc(desc);
		if (MapUtils.isNotEmpty(operations)) {
			Set<Map.Entry<Resource, Set<OperationType>>> entrySet = operations.entrySet();
			for (Map.Entry<Resource, Set<OperationType>> entry : entrySet) {
				authorize(createUser, entry.getKey(), entry.getValue());
			}
		}
	}

	public boolean authorize(User currentUser, Resource resource, OperationType operationType) {
		return authorize(currentUser, resource, operationType, new Date());
	}

	private synchronized boolean authorize(User currentUser, Resource resource, OperationType operationType, Date currentTime) {
		if (!validEntity(currentUser) || !validEntity(resource) || operationType == null) {
			return false;
		}
		if (this.operations == null) {
			this.operations = new HashMap<Resource, Operation>();
		}
		Operation operation = this.operations.get(resource);
		if (operation == null) {
			operation = new Operation(currentUser, Status.SUCCESS, operationType);
			this.operations.put(resource, operation);
		} else {
			if (hasPermission(operation, operationType)) {
				return false;
			}
			operation.addOperationTypeFrom(operationType);
			operation.setModifyTime(currentTime);
			operation.setModifyUser(currentUser);
		}
		super.setModifyTime(currentTime);
		super.setModifyUser(currentUser);
		return true;
	}

	public boolean authorize(User currentUser, Resource resource, Set<OperationType> operationTypes) {
		if (CollectionUtils.isEmpty(operationTypes)) {
			return false;
		}
		boolean result = true;
		final Date currentTime = new Date();
		for (final OperationType operationType : operationTypes) {
			result = result && !authorize(currentUser, resource, operationType, currentTime);
		}
		return !result;
	}

	public String getDesc() {
		return this.desc;
	}

	public Group getGroup() {
		return this.group;
	}

	public String getName() {
		return this.name;
	}

	public Set<Resource> getResources() {
		Set<Resource> resources = Collections.emptySet();
		if (MapUtils.isNotEmpty(this.operations)) {
			resources = Collections.unmodifiableSet(this.operations.keySet());
		}
		return resources;
	}

	public boolean hasPermission(Operation operation, OperationType operationType) {
		final Integer operationValue = !validEntity(operation) ? null : operation.getValue();
		final int accessor = operationValue == null || operationValue.intValue() < 0 ? Integer.valueOf(0) : operationValue.intValue();
		return SecurityHelper.hasPermission(accessor, operationType.getValue());
	}

	public boolean hasPermission(Resource resource, OperationType operationType) {
		if (!validEntity(resource) || operationType == null) {
			return false;
		}
		Map<Resource, Operation> operations = this.operations;
		if (MapUtils.isEmpty(operations)) {
			return false;
		}
		return hasPermission(operations.get(resource), operationType);
	}

	public void setDesc(String desc) {
		this.desc = desc;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setResources(Set<Resource> resources) {
	}

}
